package controllers

import (
	"context"
	"errors"
	"github.com/gin-gonic/gin"
	"go.didapinche.com/foundation/plat-echo/app/ops/models"
	"go.didapinche.com/foundation/plat-echo/app/ops/models/request"
	"go.didapinche.com/foundation/plat-echo/app/ops/models/response"
	"go.didapinche.com/foundation/plat-echo/app/ops/services"
	"go.didapinche.com/foundation/plat-echo/pkg/constants"
	"go.didapinche.com/uic"
	"go.uber.org/zap"
	"net/http"
	"strconv"
)

type GraphPanelController struct {
	service             services.GraphService
	accessRecordService services.AccessRecordService
	logger              *zap.Logger
}

func NewGraphPanelController(service services.GraphService, accessRecordService services.AccessRecordService, logger *zap.Logger) *GraphPanelController {
	return &GraphPanelController{
		service:             service,
		accessRecordService: accessRecordService,
		logger:              logger.With(zap.String("type", "controller.graph")),
	}
}

func (ctl *GraphPanelController) FindGraphByAppID(c *gin.Context) {
	id := c.Param("id")
	appID, err := strconv.ParseUint(id, 10, 64)
	api_id := c.Query("api_id")
	apiID, err := strconv.ParseUint(api_id, 10, 64)
	userID := c.GetString("UserID")
	graphs := &response.GraphInfo{}
	if apiID != 0 {
		graphs, err = ctl.service.FindGraphByApi(c.Request.Context(), apiID)
		if err != nil {
			if errors.Is(err, context.Canceled) {
				ctl.logger.Error("context canceled", zap.Error(err))
				c.Status(constants.StatusRequestCanceled)
				return
			}
			c.String(http.StatusInternalServerError, "call service.FindGraphByApi error:%v", err)
			ctl.logger.Error("call service.FindGraphByApi error", zap.Error(err))
			return
		}
	} else {
		graphs, err = ctl.service.FindGraphByAppID(c.Request.Context(), appID, userID)
		if err != nil {
			if errors.Is(err, context.Canceled) {
				ctl.logger.Error("context canceled", zap.Error(err))
				c.Status(constants.StatusRequestCanceled)
				return
			}
			c.String(http.StatusInternalServerError, "call service.FindGraphByAppID error:%v", err)
			ctl.logger.Error("call service.FindGraphByAppID error", zap.Error(err))
			return
		}
	}
	var name string
	var accessType models.AccessGraphType
	if graphs.Api != nil {
		name = graphs.Api.GetMethod()
		accessType = models.ApiAccess
	} else {
		name = graphs.App.Name
		accessType = models.AppAccess
	}
	ctl.accessRecordService.Create(c.Request.Context(), &models.AccessRecord{
		AppID:     appID,
		ApiID:     apiID,
		UID:       api_id,
		Name:      name,
		GraphType: accessType,
	})
	c.JSON(http.StatusOK, graphs)
}
func (ctl *GraphPanelController) FindByID(c *gin.Context) {
	id := c.Param("id")
	ID, err := strconv.ParseUint(id, 10, 64)
	if err != nil {
		c.String(http.StatusBadRequest, "bind params error:%v", err)
		ctl.logger.Error("bind params error", zap.Error(err))
		return
	}
	graphs, err := ctl.service.FindByID(c.Request.Context(), ID)
	if err != nil {
		if errors.Is(err, context.Canceled) {
			ctl.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		c.String(http.StatusInternalServerError, "call service.FindByID error:%v", err)
		ctl.logger.Error("call service.FindByID error", zap.Error(err))
		return
	}
	c.JSON(http.StatusOK, graphs)
}

//
//根据表达式和时间段信息查询prometheus数据
func (ctl *GraphPanelController) GetGraphData(c *gin.Context) {
	param := &request.GraphDataReq{}
	err := c.BindQuery(param)
	if err != nil {
		c.String(http.StatusBadRequest, err.Error())
		ctl.logger.Error("bind params error", zap.Error(err))
		return
	}
	if len(param.Expression) == 0 {
		ctl.logger.Error("expression is null", zap.Error(err))
		c.String(http.StatusBadRequest, "expression is null")
		return
	}
	data, stat, limit, min, state, err := ctl.service.GetGraphData(c.Request.Context(), param)
	if err != nil {
		if errors.Is(err, context.Canceled) {
			ctl.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		ctl.logger.Error("call service GetGraphData error", zap.Error(err))
		c.String(http.StatusInternalServerError, err.Error())
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"data":  data,
		"stat":  stat,
		"limit": limit,
		"state": state,
		"min":   min,
	})

}

func (ctl *GraphPanelController) Create(c *gin.Context) {
	req := new(models.Graph)
	if err := c.BindJSON(req); err != nil {
		ctl.logger.Error("bind params error", zap.Error(err))
		c.String(http.StatusBadRequest, "bind params error:%v", err)
		return
	}
	graph, err := ctl.service.Create(c.Request.Context(), req)
	if err != nil {
		if errors.Is(err, context.Canceled) {
			ctl.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		ctl.logger.Error("call service Create error", zap.Error(err))
		c.String(http.StatusInternalServerError, err.Error())
		return
	}
	c.JSON(http.StatusOK, graph)
}

func (ctl *GraphPanelController) Update(c *gin.Context) {
	id, err := strconv.ParseUint(c.Param("graph_id"), 10, 64)
	if err != nil {
		ctl.logger.Error("parse id err", zap.Error(err))
		c.String(http.StatusBadRequest, "parse id err:%v", err)
		return
	}
	req := new(models.Graph)
	if err := c.BindJSON(req); err != nil {
		ctl.logger.Error("bind params error", zap.Error(err))
		c.String(http.StatusBadRequest, "bind params error:%v", err)
		return
	}
	req.ID = id
	graph, err := ctl.service.Update(c.Request.Context(), req)
	if err != nil {
		if errors.Is(err, context.Canceled) {
			ctl.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		ctl.logger.Error("call service Update error", zap.Error(err))
		c.String(http.StatusInternalServerError, err.Error())
		return
	}
	c.JSON(http.StatusOK, graph)
}

func (ctl *GraphPanelController) Delete(c *gin.Context) {
	id, err := strconv.ParseUint(c.Param("id"), 10, 64)
	if err != nil {
		ctl.logger.Error("parse id err", zap.Error(err))
		c.String(http.StatusBadRequest, "parse id err:%v", err)
		return
	}

	err = ctl.service.Delete(c.Request.Context(), id)
	if err != nil {
		if errors.Is(err, context.Canceled) {
			ctl.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		ctl.logger.Error("call  service Delete error", zap.Error(err))
		c.String(http.StatusInternalServerError, err.Error())
		return
	}
	c.JSON(http.StatusOK, "ok")
}

func (ctl *GraphPanelController) UpdateGraphPosition(c *gin.Context) {
	id, err := strconv.ParseUint(c.Param("graph_id"), 10, 64)
	if err != nil {
		ctl.logger.Error("parse id err", zap.Error(err))
		c.String(http.StatusBadRequest, "parse id err:%v", err)
		return
	}
	req := new(models.GraphPosition)
	if err := c.BindJSON(req); err != nil {
		ctl.logger.Error("bind params error", zap.Error(err))
		c.String(http.StatusBadRequest, "bind params error:%v", err)
		return
	}
	err = ctl.service.UpdateGraphPosition(c.Request.Context(), id, req)
	if err != nil {
		if errors.Is(err, context.Canceled) {
			ctl.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		ctl.logger.Error("call service UpdateGraphPosition error", zap.Error(err))
		c.String(http.StatusInternalServerError, err.Error())
		return
	}
	c.JSON(http.StatusOK, "ok")
}

// 订阅
func (ctl *GraphPanelController) Subscribe(c *gin.Context) {
	id, err := strconv.ParseUint(c.Param("id"), 10, 64)
	if err != nil {
		ctl.logger.Error("convert id to integer error", zap.Error(err))
		c.String(http.StatusBadRequest, "convert id to integer error")
		return
	}
	status, err := strconv.ParseBool(c.Query("status"))
	if err != nil {
		ctl.logger.Error("convert status to bool error", zap.Error(err))
		c.String(http.StatusBadRequest, "convert status to bool error")
		return
	}

	subType, err := strconv.ParseInt(c.Query("type"), 10, 64)
	if err != nil {
		ctl.logger.Error("convert type to int error", zap.Error(err))
		c.String(http.StatusBadRequest, "convert type to int error")
		return
	}
	uid := c.GetString(uic.KeyUserID)
	err = ctl.service.Subscribe(c.Request.Context(), id, uid, status, int(subType))
	if err != nil {
		if errors.Is(err, context.Canceled) {
			ctl.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		ctl.logger.Error("call service Subscribe error", zap.Error(err))
		c.String(http.StatusNotImplemented, err.Error())
		return
	}
	c.JSON(http.StatusOK, "ok")
}

func (ctl *GraphPanelController) GetHostGraphType(c *gin.Context) {
	ip := c.Query("ip")
	name := c.Query("name")
	uid := c.GetString(uic.KeyUserID)

	graphType, err := ctl.service.FindGraphByAHostIP(c.Request.Context(), ip)
	if err != nil {
		if errors.Is(err, context.Canceled) {
			ctl.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		ctl.logger.Error("call service FindGraphByAHostIP error", zap.Error(err))
		c.String(http.StatusInternalServerError, err.Error())
		return
	}
	ctl.accessRecordService.Create(c.Request.Context(), &models.AccessRecord{
		IP:        ip,
		UID:       uid,
		Name:      name,
		GraphType: models.HostAccess,
	})

	c.JSON(http.StatusOK, graphType)
}

func (ctl *GraphPanelController) FindByDashboardID(c *gin.Context) {
	id, err := strconv.ParseUint(c.Param("id"), 10, 64)
	if err != nil {
		ctl.logger.Error("parse id err", zap.Error(err))
		c.String(http.StatusBadRequest, "parse id err:%v", err)
		return
	}
	uid := c.GetString(uic.KeyUserID)
	graphTypes, dashboard, err := ctl.service.FindByDashboardID(c.Request.Context(), id, uid)
	if err != nil {
		if errors.Is(err, context.Canceled) {
			ctl.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		ctl.logger.Error("call service FindByDashboardID error", zap.Error(err))
		c.String(http.StatusInternalServerError, err.Error())
		return
	}
	ctl.accessRecordService.Create(c.Request.Context(), &models.AccessRecord{
		DashboardID: id,
		UID:         uid,
		Name:        dashboard.Name,
		GraphType:   models.DashboardAccess,
	})
	c.JSON(http.StatusOK, graphTypes)
}

func (ctl *GraphPanelController) UpdateGraphType(c *gin.Context) {
	id, err := strconv.ParseUint(c.Param("graph_id"), 10, 64)
	if err != nil {
		ctl.logger.Error("parse id error", zap.Error(err))
		c.String(http.StatusBadRequest, "parse id err:%v", err)
		return
	}
	req := new(request.GraphTypeReq)
	if err := c.BindJSON(req); err != nil {
		ctl.logger.Error("bind params error", zap.Error(err))
		c.String(http.StatusBadRequest, "bind params error:%v", err)
		return
	}
	err = ctl.service.UpdateGraphType(c.Request.Context(), id, req)
	if err != nil {
		if errors.Is(err, context.Canceled) {
			ctl.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		ctl.logger.Error("call service UpdateGraphType error", zap.Error(err))
		c.String(http.StatusInternalServerError, err.Error())
		return
	}
	c.JSON(http.StatusOK, "ok")
}

// 告警静默
func (ctl *GraphPanelController) UpdateSilence(c *gin.Context) {
	id, err := strconv.ParseUint(c.Param("graph_id"), 10, 64)
	if err != nil {
		ctl.logger.Error("parse id err", zap.Error(err))
		c.String(http.StatusBadRequest, "parse id err:%v", err)
		return
	}
	params := new(models.Silence)
	err = c.BindJSON(params)
	if err != nil {
		ctl.logger.Error("bind param json error", zap.Error(err))
		c.String(http.StatusBadRequest, err.Error())
		return
	}

	err = ctl.service.UpdateSilence(c.Request.Context(), id, params)
	if err != nil {
		if errors.Is(err, context.Canceled) {
			ctl.logger.Error("context canceled", zap.Error(err))
			c.Status(constants.StatusRequestCanceled)
			return
		}
		ctl.logger.Error("call service UpdateSilence error", zap.Error(err))
		c.String(http.StatusInternalServerError, err.Error())
		return
	}
	c.JSON(http.StatusOK, "ok")
}

func (ctl *GraphPanelController) ClearApiK8s(c *gin.Context) {
	err := ctl.service.ClearApiK8s(c.Request.Context())
	if err != nil {
		c.String(http.StatusInternalServerError, err.Error())
		return
	}
	c.JSON(http.StatusOK, "ok")
}
